/**
 *  StaDiUM - State Diagram Unified Modeler
 *  Copyright (C) 2007  Stefan Bucur, Mihai Balan, Claudiu Tanase
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/**
 *  File Information
 *
 *  Last Modified On: $Date: 2007-06-14 10:38:48 +0000 (Thu, 14 Jun 2007) $
 *  Last Modified By: $Author: stefan.bucur $
 */

package ro.pub.cs.stadium.input.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import ro.pub.cs.stadium.document.IDocument;
import ro.pub.cs.stadium.document.IState;
import ro.pub.cs.stadium.document.ITransition;
import ro.pub.cs.stadium.platform.IPluginProvider;
import ro.pub.cs.stadium.plugin.IDocumentPlugin;
import ro.pub.cs.stadium.plugin.IInputPlugin;
import ro.pub.cs.stadium.plugin.IPlugin;
import ro.pub.cs.stadium.plugin.PluginInfo;
import ro.pub.cs.stadium.plugin.PluginSettings;
import ro.pub.cs.stadium.plugin.PluginType;

/**
 * Implements the XML input serialization for diagram document
 * @author stefan
 *
 */
public class InputXMLPlugin implements IPlugin, IInputPlugin {
	private final String docFormat = "XML";
	
	private DocumentBuilderFactory documentFactory;
	private DocumentBuilder documentBuilder;
	private Document inputDocument;
	
	private PluginSettings mySettings = null;
	
	private IDocument getDocumentFromDocType(String docType) {
		IPluginProvider plugProv = mySettings.getPluginProvider();
		
		IDocumentPlugin docPlugin = plugProv.getDocumentPlugin(docType);
		
		if (docPlugin == null)
			return null;
		
		return docPlugin.createNewDocument();
	}

	/**
	 * Returns an instance of the specific plugin implementation
	 */
	public Object getPlugin(PluginType type) {
		if (type == PluginType.INPUT)
			return this;
		else
			return null;
	}

	/**
	 * Returns a list of supported plugins
	 */
	public PluginType[] getPluginImplementations() {
		return new PluginType[] {PluginType.INPUT};
	}

	/**
	 * Reads an IDocument from a given XML file
	 */
	public IDocument readDocument(InputStream stream) {
		IDocument result = null;
		IState crtState;
		ITransition crtTransition;
		Map<String, String> itemAttrib;
		String itemName, startState, endState;
		Map<String, IState> states;
		Map<String, ITransition> transitions;
		
		Element docRoot;
		NodeList elements, elementsAttributes;
		Node crtNode, crtAttribElement;
		NamedNodeMap attributes;
		
		try {
			inputDocument = documentBuilder.parse(stream);
			docRoot = inputDocument.getDocumentElement();
			result = getDocumentFromDocType(docRoot.getAttribute("doctype"));
			
			elements = docRoot.getElementsByTagName("state");
			states = result.getStates();
			/* Retrieve states */
			for(int i = 0; i< elements.getLength(); i++) {
				crtNode = elements.item(i);
				itemName =
					crtNode.getAttributes().getNamedItem("name").getNodeValue();
				crtState = result.createNewState(itemName);
				elementsAttributes = ((Element)elements.item(i)).getElementsByTagName("attribute");
				itemAttrib = crtState.getAttributes();
				
				/* Adding attributes */
				for(int j = 0; j < elementsAttributes.getLength(); j++) {
					crtAttribElement = elementsAttributes.item(j);
					itemAttrib.put(crtAttribElement.getAttributes().getNamedItem("name").getNodeValue(),
							crtAttribElement.getNodeValue());
				}
				
				states.put(itemName, crtState);
			}
			
			elements = docRoot.getElementsByTagName("transition");
			transitions = result.getTransitions();
			for(int i = 0; i< elements.getLength(); i++) {
				crtNode = elements.item(i);
				itemName = 
					crtNode.getAttributes().getNamedItem("name").getNodeValue();
				startState =
					crtNode.getAttributes().getNamedItem("start").getNodeValue();
				endState =
					crtNode.getAttributes().getNamedItem("end").getNodeValue();

				crtTransition = result.createNewTransition(itemName);
				crtTransition.setStartPoint(result.getStates().get(startState));
				crtTransition.setEndPoint(result.getStates().get(endState));

				itemAttrib = crtTransition.getAttributes();
				
				elementsAttributes = ((Element)elements.item(i)).getElementsByTagName("attribute");

				for(int j = 0; j < elementsAttributes.getLength(); j++) {
					crtAttribElement = elementsAttributes.item(j);
					itemAttrib.put(crtAttribElement.getAttributes().getNamedItem("name").getNodeValue(),
							crtAttribElement.getNodeValue());
				}
				
				transitions.put(itemName, crtTransition);
			}
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * Executes the plugin initialization procedure
	 */
	public void initialise(PluginSettings settings) {
		this.mySettings = settings;
		try {
			documentFactory = DocumentBuilderFactory.newInstance();
			documentBuilder = documentFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	public PluginInfo getPluginInfo() {
		return new PluginInfo("XML input plugin v0.1a", null);
	}

	/* (non-Javadoc)
	 * @see ro.pub.cs.stadium.plugin.IInputPlugin#getDocumentFormat()
	 */
	public String getDocumentFormat() {
		return docFormat;
	}
	
	
}